package de.fhffm.scs.simulator.gui;

import java.util.concurrent.TimeUnit;

import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import de.fhffm.scs.simulator.body.Body;
import de.fhffm.scs.simulator.body.SimulationBody;
import de.fhffm.scs.simulator.data.BloodSugarLevel;
import de.fhffm.scs.simulator.driver.IndicatorDriver;
import de.fhffm.scs.simulator.driver.InjectorDriver;
import de.fhffm.scs.simulator.driver.InjectorDriverImpl;
import de.fhffm.scs.simulator.driver.NullIndicator;
import de.fhffm.scs.simulator.driver.SensorDriver;
import de.fhffm.scs.simulator.driver.SensorDriverImpl;
import de.fhffm.scs.simulator.food.FeedSimulator;
import de.fhffm.scs.simulator.hardware.Injector2000Impl;
import de.fhffm.scs.simulator.hardware.Sensor2000Impl;
import de.fhffm.scs.simulator.hardware.SensorHardware;
import de.fhffm.scs.simulator.regulator.BasicUnitCalc;
import de.fhffm.scs.simulator.regulator.BloodSugarEstimator;
import de.fhffm.scs.simulator.regulator.BloodSugarLevelEstimator;
import de.fhffm.scs.simulator.regulator.SugarLevelController;
import de.fhffm.scs.simulator.regulator.SugarLevelControllerImpl;
import de.fhffm.scs.simulator.regulator.UnitCalc;
import de.fhffm.scs.simulator.scheduler.SimulationScheduler;

public class Simulation {

    private static DateTimeFormatter FORMAT = DateTimeFormat.forPattern("HH:mm");

    private final int SCHEDULER_SPEED = 1 * 60 * 12;

    SimulationBody body;
    SensorDriver sensorDriver;
    InjectorDriver injectionDriver;
    IndicatorDriver indicationDriver;

    SensorHardware sensorHardware;
    Injector2000Impl injectionHardware;
    SugarLevelController controller;
    UnitCalc unitCalc;
    BloodSugarEstimator estimator;

    SimulationScheduler scheduler;

    public Simulation() {
        scheduler = new SimulationScheduler(FORMAT.parseDateTime("7:00").getMillis());
        scheduler.setSimulationSpeed(SCHEDULER_SPEED);
        scheduler.start();

        body = new SimulationBody(scheduler);

        sensorHardware = new Sensor2000Impl(body, scheduler);
        injectionHardware = new Injector2000Impl(body);

        sensorDriver = new SensorDriverImpl(sensorHardware, scheduler,
            TimeUnit.SECONDS, 5);
        injectionDriver = new InjectorDriverImpl(injectionHardware);

        estimator = new BloodSugarLevelEstimator();

        unitCalc = new BasicUnitCalc() {

            @Override
            public int getUnitsNeededToReduceBloodSugarLevel(BloodSugarLevel futureBSL) {
                return 2;
            }
        };
        
        indicationDriver = new NullIndicator();

        controller = new SugarLevelControllerImpl(injectionDriver, indicationDriver, scheduler, unitCalc, estimator);

        sensorDriver.addObserver(controller);

        Thread autoRead = new Thread(sensorDriver);
        autoRead.setName("AutoRead");
        autoRead.start();

        body.start();

        FeedSimulator feeder = new FeedSimulator(body, scheduler);
        feeder.start();
    }

    public static void main(String[] args) {
        Simulation s = new Simulation();
        final SimulationWindow window = new SimulationWindow(s);
        window.open();

    }
    
    public void setIndicationDriver(IndicatorDriver indicatorDriver){
        this.indicationDriver = indicatorDriver;
        this.controller.registerIndicationDriver(indicatorDriver);
    }

    public Body getBody() {
        return body;
    }

    public SugarLevelController getController() {
        return controller;
    }

}
